Java8 读取、写入、遍历、监控文件及目录

您所在的位置:网站首页 Java 文件写入追加 Java8 读取、写入、遍历、监控文件及目录

Java8 读取、写入、遍历、监控文件及目录

#Java8 读取、写入、遍历、监控文件及目录| 来源: 网络整理| 查看: 265

JavaDoc:https://javadocs.techempower.com/

文章目录 一、读取文件1. Java 8 Stream按行读取文件2. FileReader 按行读取文件3. try-with-resources模式自动关闭流 二、写入文件1. Java 8使用BufferedWriter写入文件2. 使用Files.write()写入文件 三、遍历迭代目录1. Files.list()–遍历所有文件和子目录2. Files.list()–仅列出不包括子目录的文件3. Files.newDirectoryStream()–列出所有文件和子目录4. Files.newDirectoryStream()–仅迭代不包含子目录的文件5. 仅列出一定范围的所有文件6. 查找目录中的所有隐藏文件 四、监视目录,子目录和文件中的更改1. 如何注册WatchService2. 观察变化事件3. 监视目录,子目录和文件中的更改示例

一、读取文件

参考链接:https://howtodoinjava.com/java8/read-file-line-by-line-in-java-8-streams-of-lines-example/

在下面的实例中,将使用Stream来一行一行的读取文件。将要读取的文件 data.txt 内容如下:

Never store password except in mind.

将上面的文件一行一行的读取,如果有一行包含 password ,将这行打印出来

1. Java 8 Stream按行读取文件

利用Java 8 Stream按行读取文件内容,过滤包含 password 的行,并取出第一条打印出来

private static void readStreamOfLinesUsingFiles() throws IOException { Stream lines = Files.lines(Paths.get("c:/temp", "data.txt")); Optional hasPassword = lines.filter(s -> s.contains("password")).findFirst(); if(hasPassword.isPresent()) { System.out.println(hasPassword.get()); } //Close the stream and it's underlying file as well lines.close(); } 2. FileReader 按行读取文件

直到java7,可采用下面的方式来读取文件,实现方法有很多,但不是本文的重点,只是与上面的例子对比来看

private static void readLinesUsingFileReader() throws IOException { File file = new File("c:/temp/data.txt"); FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); String line; while((line = br.readLine()) != null) { if(line.contains("password")){ System.out.println(line); } } br.close(); fr.close(); } 3. try-with-resources模式自动关闭流

第一个例子已经能够满足我们在应用程序中逐行读取文件的需要了,但如果你还想让它变得更好,那么我们可以使用 try-with-resources 的方式,这样会省去最后关闭流 close() 的操作。

private static void readStreamOfLinesUsingFilesWithTryBlock() throws IOException { Path path = Paths.get("c:/temp", "data.txt"); //The stream hence file will also be closed here try(Stream lines = Files.lines(path)) { Optional hasPassword = lines.filter(s -> s.contains("password")).findFirst(); if(hasPassword.isPresent()){ System.out.println(hasPassword.get()); } } }

当一个Stream产生另外一个Stream的时候,close 方法会链式调用(它下面的Stream也会调用),可以采用下面的方法编写:

private static void readStreamOfLinesUsingFilesWithTryBlock() throws IOException { Path path = Paths.get("c:/temp", "data.txt"); //When filteredLines is closed, it closes underlying stream as well as underlying file. try(Stream filteredLines = Files.lines(path).filter(s -> s.contains("password"))) { Optional hasPassword = filteredLines.findFirst(); if(hasPassword.isPresent()){ System.out.println(hasPassword.get()); } } }

你想测试一下它下面的Stream的有没有触发 close ,可以用 onClose 来测试一下

private static void readStreamOfLinesUsingFilesWithTryBlock() throws IOException { Path path = Paths.get("c:/temp", "data.txt"); //When filteredLines is closed, it closes underlying stream as well as underlying file. try(Stream filteredLines = Files.lines(path) //test if file is closed or not .onClose(() -> System.out.println("File closed")) .filter(s -> s.contains("password"))){ Optional hasPassword = filteredLines.findFirst(); if(hasPassword.isPresent()){ System.out.println(hasPassword.get()); } } }

输出

password File closed 二、写入文件

参考链接:https://howtodoinjava.com/java8/java-8-write-to-file-example/

1. Java 8使用BufferedWriter写入文件

BufferedWriter 用于将文本写入字符或字节流。在打印字符之前,它将字符存储在缓冲区中,并批量打印。如果没有缓冲,每次调用 print () 方法都会导致字符转换为字节,然后立即写入文件,效率会很低。

//Get the file reference Path path = Paths.get("c:/output.txt"); //Use try-with-resource to get auto-closeable writer instance try (BufferedWriter writer = Files.newBufferedWriter(path)) { writer.write("Hello World !!"); } 2. 使用Files.write()写入文件

使用 Files.write() 也很漂亮简洁.

String content = "Hello World !!"; Files.write(Paths.get("c:/output.txt"), content.getBytes()); 三、遍历迭代目录

参考链接:https://howtodoinjava.com/java8/java-8-list-all-files-example/

学习使用Java 8 API,例如Files.list()和DirectoryStream,并递归列出目录中存在的所有文件,包括隐藏文件。

对于使用外部迭代(用于循环),请使用DirectoryStream。要使用Stream API操作(映射,过滤,排序,收集),请Files.list()改用。

1. Files.list()–遍历所有文件和子目录

Files.list() 方法 遍历当前目录下所有的文件和子目录

Files.list(Paths.get(".")) .forEach(System.out::println); // 或者 List files = Files.list(Paths.get(dirLocation)) .map(Path::toFile) .collect(Collectors.toList()); files.forEach(System.out::println); Output: .\filename1.txt .\directory1 .\filename2.txt .\Employee.java 2. Files.list()–仅列出不包括子目录的文件

使用过滤器表达式 Files::isRegularFile 检查文件是否是普通文件,来过滤掉子目录,保留文件并打印

Files.list(Paths.get(".")) .filter(Files::isRegularFile) .forEach(System.out::println); // 或者 List files = Files.list(Paths.get(".")) .filter(Files::isRegularFile) .map(Path::toFile) .collect(Collectors.toList()); files.forEach(System.out::println); Output: .\filename1.txt .\filename2.txt .\Employee.java 3. Files.newDirectoryStream()–列出所有文件和子目录

Java提供了一个更加灵活遍历目录内容的方式:Files.newDirectoryStream()

注意,如果对一个大的目录进行操作,使用 DirectoryStream 将提高代码的运行速度

Files.newDirectoryStream(Paths.get(".")) .forEach(System.out::println); Output: .\filename1.txt .\directory1 .\filename2.txt .\Employee.java 4. Files.newDirectoryStream()–仅迭代不包含子目录的文件

只遍历文件,排除掉目录,通过path filter的第二个参数来控制

Files.newDirectoryStream(Paths.get("."), path -> path.toFile().isFile()) .forEach(System.out::println); Output: .\filename1.txt .\filename2.txt .\Employee.java 5. 仅列出一定范围的所有文件

要仅获取某些扩展名的所有文件的列表,请同时使用两个谓词 Files::isRegularFile和path.toString().endsWith(".java")。

使用上述谓词,我们将列出.java文件夹中的所有文件。

Files.newDirectoryStream(Paths.get("."), path -> path.toString().endsWith(".java")) .forEach(System.out::println); // 或者 List files = Files.list(Paths.get(dirLocation)) .filter(Files::isRegularFile) .filter(path -> path.toString().endsWith(".java")) .map(Path::toFile) .collect(Collectors.toList()); files.forEach(System.out::println); Output: .\Employee.java 6. 查找目录中的所有隐藏文件

要查找所有隐藏文件,可以file -> file.isHidden()在上述任何示例中使用过滤器表达式。

final File[] files = new File(".").listFiles(file -> file.isHidden()); // 或者 方法引用写法 final File[] files = new File(".").listFiles(File::isHidden); // 或者 使用Files工具类 List files = Files.list(Paths.get(".")) .filter(path -> path.toFile().isHidden()) .map(Path::toFile) .collect(Collectors.toList()); 四、监视目录,子目录和文件中的更改

参考链接:https://howtodoinjava.com/java8/java-8-watchservice-api-tutorial/

在此将使用 Java 7 WatchServiceAPI观察目录及其中的所有子目录和文件。WatchService 是jdk1.7版本引进的,位于 java.nio.file 包下。WatchService 是基于本机操作系统实现对文件的监控。

1. 如何注册WatchService

要注册WatchService,请获取目录路径并使用path.register()方法。

Path path = Paths.get("."); WatchService watchService = path.getFileSystem().newWatchService(); path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY); 2. 观察变化事件

要获取目录及其中文件的更改,请使用watchKey.pollEvents()方法,该方法以流的形式返回所有更改事件的集合。

WatchKey watchKey = null; while (true) { watchKey = watchService.poll(10, TimeUnit.MINUTES); if(watchKey != null) { watchKey.pollEvents().stream().forEach(event -> System.out.println(event.context())); } watchKey.reset(); }

该密钥一直有效,直到:

通过调用它的cancel方法显式地取消它,或者隐式取消,因为该对象不再可访问,或者通过关闭手表服务。

如果要在循环中多次重复使用同一键来获取更改事件,请不要忘记调用 watchKey.reset() 将键重新设置为就绪状态的方法。

请注意,诸如如何检测事件,其及时性以及是否保留其顺序之类的几件事高度依赖于底层操作系统。某些更改可能导致一个操作系统中的单个条目,而类似的更改可能导致另一操作系统中的多个事件。

3. 监视目录,子目录和文件中的更改示例

在此示例中,我们将看到一个观看目录的示例,该目录中包含所有子目录和文件。我们将维护监视键和目录的映射,Map keys以正确识别已修改的目录。

下面的方法将向观察者注册一个path,然后将path和key存储在map中。

private void registerDirectory(Path dir) throws IOException { WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); keys.put(key, dir); }

在遍历目录结构并为遇到的每个目录调用此方法时,将递归调用此方法。

private void walkAndRegisterDirectories(final Path start) throws IOException { // register directory and sub-directories Files.walkFileTree(start, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { registerDirectory(dir); return FileVisitResult.CONTINUE; } }); }

请注意,无论何时创建新目录,我们都会在 watchservice 中注册该目录,并将新key添加到map中。

WatchEvent.Kind kind = event.kind(); if (kind == ENTRY_CREATE) { try { if (Files.isDirectory(child)) { walkAndRegisterDirectories(child); } } catch (IOException x) { // do something useful } }

将以上所有内容与处理事件的逻辑放在一起,完整的示例如下所示:

import static java.nio.file.StandardWatchEventKinds.*; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.nio.file.attribute.BasicFileAttributes; import java.util.HashMap; import java.util.Map; public class Java8WatchServiceExample { private final WatchService watcher; private final Map keys; /** * Creates a WatchService and registers the given directory */ Java8WatchServiceExample(Path dir) throws IOException { this.watcher = FileSystems.getDefault().newWatchService(); this.keys = new HashMap(); walkAndRegisterDirectories(dir); } /** * Register the given directory with the WatchService; This function will be called by FileVisitor */ private void registerDirectory(Path dir) throws IOException { WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); keys.put(key, dir); } /** * Register the given directory, and all its sub-directories, with the WatchService. */ private void walkAndRegisterDirectories(final Path start) throws IOException { // register directory and sub-directories Files.walkFileTree(start, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { registerDirectory(dir); return FileVisitResult.CONTINUE; } }); } /** * Process all events for keys queued to the watcher */ void processEvents() { for (;;) { // wait for key to be signalled WatchKey key; try { key = watcher.take(); } catch (InterruptedException x) { return; } Path dir = keys.get(key); if (dir == null) { System.err.println("WatchKey not recognized!!"); continue; } for (WatchEvent event : key.pollEvents()) { @SuppressWarnings("rawtypes") WatchEvent.Kind kind = event.kind(); // Context for directory entry event is the file name of entry @SuppressWarnings("unchecked") Path name = ((WatchEvent)event).context(); Path child = dir.resolve(name); // print out event System.out.format("%s: %s\n", event.kind().name(), child); // if directory is created, and watching recursively, then register it and its sub-directories if (kind == ENTRY_CREATE) { try { if (Files.isDirectory(child)) { walkAndRegisterDirectories(child); } } catch (IOException x) { // do something useful } } } // reset key and remove from set if directory no longer accessible boolean valid = key.reset(); if (!valid) { keys.remove(key); // all directories are inaccessible if (keys.isEmpty()) { break; } } } } public static void main(String[] args) throws IOException { Path dir = Paths.get("c:/temp"); new Java8WatchServiceExample(dir).processEvents(); } }

运行该程序,并在给定输入目录中,新增更改文件或者目录后,您将在控制台中注意到捕获的事件。

输出: ENTRY_CREATE:c:\ temp \ New文件夹 ENTRY_DELETE:c:\ temp \ New文件夹 ENTRY_CREATE:c:\ temp \ data ENTRY_CREATE:c:\ temp \ data \ New Text Document.txt ENTRY_MODIFY:c:\ temp \ data ENTRY_DELETE:c:\ temp \ data \ New Text Document.txt ENTRY_CREATE:c:\ temp \ data \ tempFile.txt ENTRY_MODIFY:c:\ temp \ data ENTRY_MODIFY:c:\ temp \ data \ tempFile.txt ENTRY_MODIFY:c:\ temp \ data \ tempFile.txt ENTRY_MODIFY:c:\ temp \ data \ tempFile.txt

WatchService 需要牢记两件事:

WatchService 不会为监视目录的子目录拾取事件。我们仍然需要轮询 WatchService 的事件,而不是接收异步通知。WatchService能立即监控到文件的改动。 如果事件是创建,删除或更新,并且该事件相对于监视目录,则 WatchEvent.context 方法将返回Path对象。 重要的是要知道,当收到事件时,不能保证执行该操作的程序已经完成,因此可能需要一定程度的协调,比如判断文件操作成功。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3